﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StockMonitor.Configuration;
using CarolLib;

namespace StockMonitor.Business
{
    /// <summary>
    /// MA计算器，包括
    /// </summary>
    /// <remarks>
    /// 代码编写：<author>LANCEZHANG-PC\zhangxl</author><br/>
    /// 编写时间：<datetime>2012-10-16 4:43 PM</datetime>
    /// </remarks>
    public class MACalculator : ICaptialCalculator
    {
        #region Members

        public int[] Config;

        bool isInited = false;
        List<double> historyPrice;
        List<double> lastCaptials;
        List<double> currentCaptials;

        #endregion

        #region ICaptialCalculator Members

        /// <summary>
        /// 计算器标识
        /// </summary>
        /// <remarks>
        /// 代码编写：<author>LANCEZHANG-PC\zhangxl</author><br/>
        /// 编写时间：<datetime>2012-10-16 4:43 PM</datetime>
        /// </remarks>
        public string Key { get { return "MA"; } }

        /// <summary>
        /// 股票代码
        /// </summary>
        /// <remarks>
        /// 代码编写：<author>LANCEZHANG-PC\zhangxl</author><br/>
        /// 编写时间：<datetime>2012-10-16 4:43 PM</datetime>
        /// </remarks>
        public string StockCode { get; set; }

        /// <summary>
        /// 初始化指标计算器
        /// </summary>
        /// <param name="stockCode">股票代码</param>
        /// <remarks>
        /// 代码编写：<author>LANCEZHANG-PC\zhangxl</author><br/>
        /// 编写时间：<datetime>2012-10-16 4:43 PM</datetime>
        /// </remarks>
        public void Init(string stockCode)
        {
            Config = AppSettings.GetValue<string>("MAParams", "3|5|21", true).Split('|').Select(p => int.Parse(p)).ToArray();

            if (string.IsNullOrEmpty(stockCode))
                throw new ArgumentNullException("stockCode", "指标初始化错误，必须指定股票代码");

            this.StockCode = stockCode;
            historyPrice = BusinessFactory.GetHistoryPriceProvider().GetHistoryClosePrice(stockCode, 100);
            lastCaptials = GetSMAs(Config, historyPrice);

            isInited = true;
        }

        /// <summary>
        /// 检测指标信号
        /// </summary>
        /// <param name="currentPrice">当前价格</param>
        /// <returns>
        /// 应发信号
        /// </returns>
        /// <remarks>
        /// 代码编写：<author>LANCEZHANG-PC\zhangxl</author><br/>
        /// 编写时间：<datetime>2012-10-16 4:43 PM</datetime>
        /// </remarks>
        public Enums.Signal DetectSignal(double currentPrice)
        {
            if (!isInited)
                this.Init(StockCode);

            currentCaptials = GetSMAs(Config, historyPrice, currentPrice);

            var rules = CrossSignalRuleConfig.GetRules(this.Key);

            var tempsg = Enums.Signal.None;

            //逐个检查所配置的规则，若有触发，则发出信号
            foreach (var rule in rules)
            {
                var signal = rule.Check(lastCaptials, currentCaptials);
                if (signal != Enums.Signal.None)
                {
                    if (signal == Enums.Signal.Buy || signal == Enums.Signal.Sell) //如果买卖，则记录信号
                    {
                        tempsg = signal;
                    }
                    else if (signal == Enums.Signal.BuyAppend || signal == Enums.Signal.SellAppend) //如果买卖，则记录信号
                    {
                        var stock = signal == Enums.Signal.BuyAppend ? StockPool.Instance.BuyPool.Find(s => s.StockCode == StockCode) : StockPool.Instance.SellPool.Find(s => s.StockCode == StockCode);
                        
                        //先BuyAppend再SellAppend和前一天的参数比（M1<M3），先发出BuyAppend（M1>M3）时，
                        //由于股市动荡，在一天内有出现M1<M3，此时先检测BuyAppend的出发时间，如果为同一天，
                        //则接着检测此时是否M1>M2, 如果是，则为假信号，不触发SellAppend；如果否，则触发SellAppend。
                        //begin
                        if (stock != null && stock.LastAppendTrigger > DateTime.Today)
                        {
                            bool isSell = signal == Enums.Signal.SellAppend;
                            bool M1dayuM2 = currentCaptials[0] > currentCaptials[1];

                            if ((isSell && M1dayuM2) || (!isSell && !M1dayuM2))
                                break;
                        }
                        //end

                        if (tempsg != Enums.Signal.None && ((int)signal == (int)tempsg * 2))  //如果附加买卖，且此时已记录买卖信号，则转换成买带附加买，卖带附加卖
                        {
                            tempsg = (Enums.Signal)((int)tempsg * 3);
                            break;
                        }
                        else  //单纯附加买，附加卖，直接发出
                        {
                            tempsg = signal;
                            break;
                        }
                    }
                }
            }

            lastCaptials = currentCaptials;
            return tempsg;
        }

        /// <summary>
        /// 获取当前价，并检测指标信号
        /// </summary>
        /// <returns>
        /// 应发信号
        /// </returns>
        /// <remarks>
        /// 代码编写：<author>LANCEZHANG-PC\zhangxl</author><br/>
        /// 编写时间：<datetime>2012-10-16 4:43 PM</datetime>
        /// </remarks>
        public Enums.Signal DetectSignal()
        {
            double currentPrice = 0.0;
            try
            {
                BusinessFactory.GetCurrentPriceProvider().GetCurrentPrice(StockCode);
            }
            catch (Exception e)
            {
                Log.Exception("行情价格获取失败，请检查系统配置", e);
            }

            return DetectSignal(currentPrice);
        }

        #endregion

        #region Private Methods.

        private double GetSMA(int index, List<double> historyClosePrice)
        {
            //历史数据不够
            if (index > historyClosePrice.Count)
                return 0;

            double sum = 0;
            for (int i = 0; i < index; i++)
            {
                sum += historyClosePrice[historyClosePrice.Count - 1 - i];
            }

            return sum / index;
        }

        private double GetSMA(int index, List<double> historyClosePrice, double currentPrice)
        {
            List<double> newPrices = new List<double>(historyClosePrice);
            newPrices.Add(currentPrice);

            return GetSMA(index, newPrices);
        }

        private List<double> GetSMAs(int[] indexs, List<double> historyClosePrice)
        {
            List<double> result = new List<double>();

            indexs.ToList().ForEach(i => result.Add(GetSMA(i, historyClosePrice)));

            return result;
        }

        private List<double> GetSMAs(int[] indexs, List<double> historyClosePrice, double currentPrice)
        {
            List<double> result = new List<double>();

            indexs.ToList().ForEach(i => result.Add(GetSMA(i, historyClosePrice, currentPrice)));

            return result;
        }

        #endregion
    }
}
